package com.my.socket.nio.v8;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * Created by Scarlett on 2018/7/2 0002.
 */
public abstract class SocketHandler implements Runnable {
    protected final Logger LOGGER = LoggerFactory.getLogger(getClass());
    protected ServerDispatcher serverDispatcher;
    protected ServerSocketChannel serverSocketChannel;
    protected Selector selector;
    protected SocketChannel socketChannel;

    private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();

    public SocketHandler(ServerDispatcher serverDispatcher, ServerSocketChannel serverSocketChannel, Selector selector) {
        this.serverDispatcher = serverDispatcher;
        this.serverSocketChannel = serverSocketChannel;
        this.selector = selector;
    }

    public abstract void runnerExecute(int readyKeyOps) throws IOException;

    public final void run() {
        while (true) {
            readWriteLock.readLock().lock();
            try {
                int keyOps = this.Select();

                runnerExecute(keyOps);

                Thread.sleep(1000);
            } catch (Exception e) {
                LOGGER.error(e.getMessage());
            } finally {
                readWriteLock.readLock().unlock();
            }
        }
    }

    private int Select() throws IOException {
        int keyOps = this.selector.selectNow();

        boolean flag = keyOps > 0;

        if (flag) {
            Set<SelectionKey> readyKeySet = selector.selectedKeys();
            Iterator<SelectionKey> iterator = readyKeySet.iterator();
            while (iterator.hasNext()) {
                SelectionKey key = iterator.next();
                iterator.remove();
                keyOps = key.readyOps();
                if (keyOps == SelectionKey.OP_READ || keyOps == SelectionKey.OP_WRITE) {
                    socketChannel = (SocketChannel) key.channel();
                    socketChannel.configureBlocking(false);
                }
            }
        }

        return keyOps;
    }

}
